package file

import (
	"context"
	"strconv"
	"strings"

	"mall/common/globalkey"
	"mall/common/modelx"
	"mall/service/attachment/model"
	"mall/service/attachment/rpc/internal/svc"
	"mall/service/attachment/rpc/internal/utils/errorhandler"
	"mall/service/attachment/rpc/types/attachment"
	"mall/service/backend/common/utils/pointy"

	"github.com/zeromicro/go-zero/core/logx"
)

type BackendGetFileListLogic struct {
	ctx    context.Context
	svcCtx *svc.ServiceContext
	logx.Logger
}

func NewBackendGetFileListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *BackendGetFileListLogic {
	return &BackendGetFileListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logx.WithContext(ctx),
	}
}

func (l *BackendGetFileListLogic) BackendGetFileList(in *attachment.FileListReq) (*attachment.FileListResp, error) {
	var orderBys []string
	var relOrderBys []string
	if len(in.OrderBy) > 0 {
		for _, orderBy := range in.OrderBy {
			var order string = " ASC"
			if orderBy.Order == "1" {
				order = " DESC"
			}
			switch orderBy.Field {
			case "id":
				orderBys = append(orderBys, model.AttachmentColumns.ID+order)
			case "sort":
				orderBys = append(orderBys, model.AttachmentColumns.MenuOrder+order)
				relOrderBys = append(relOrderBys, model.AttachmentTermRelationshipColumns.TermOrder+order)
			case "filename":
				orderBys = append(orderBys, model.AttachmentColumns.PostName+order)
			case "createdAt":
				orderBys = append(orderBys, model.AttachmentColumns.PostDate+order)
			}
		}
	}
	if len(orderBys) == 0 {
		orderBys = append(orderBys, model.AttachmentColumns.ID+" DESC")
	}

	var stati string
	if len(in.FilterBy) > 0 {
		for _, filterBy := range in.FilterBy {
			if filterBy.Field == "status" {
				stati = filterBy.In
			}
		}
	}

	var page uint64
	var pageSize uint64
	var restricted bool
	filterMap := make(map[string]map[string][]any)
	resp := &attachment.FileListResp{}
	var termIds []any
	if len(in.CategoryIds) > 0 || len(in.TagIds) > 0 {
		if len(in.CategoryIds) > 0 {
			for _, cid := range in.CategoryIds {
				if cid > 0 {
					termIds = append(termIds, cid)
				}
			}
		}
		if len(termIds) == 0 && len(in.TagIds) > 0 {
			for _, tid := range in.TagIds {
				if tid > 0 {
					termIds = append(termIds, tid)
				}
			}
		}
	}
	if len(termIds) > 0 {
		preFilterMap := make(map[string]map[string][]any)
		preFilterMap[model.AttachmentTermRelationshipColumns.TermID] = map[string][]any{
			"in": termIds,
		}
		if in.Ids != nil {
			if vals := modelx.UniqueInterfaces(strings.TrimSpace(*in.Ids), 64); len(vals) > 0 {
				filterMap[model.AttachmentTermRelationshipColumns.ObjectID] = map[string][]any{
					"in": vals,
				}
				restricted = true
			}
		}
		if !restricted {
			page = in.Page
			pageSize = in.PageSize
		}
		list, _, err := l.svcCtx.MediaTerm.GetRelationshipList(l.ctx, model.M{
			"page":     page,
			"pageSize": pageSize,
			"orderBy":  strings.Join(relOrderBys, ","),
			"select":   ",",
		}, 1, preFilterMap)
		if err != nil {
			return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
		}

		if len(list) > 0 {
			var ids []any
			for _, v := range list {
				ids = append(ids, v.ObjectID)
			}
			filterMap[model.AttachmentColumns.ID] = map[string][]any{
				"in": ids,
			}
		}
	} else if in.Ids != nil {
		if vals := modelx.UniqueInterfaces(*in.Ids, 64); len(vals) == 0 {
			return resp, nil
		} else {
			filterMap[model.AttachmentColumns.ID] = map[string][]any{
				"in": vals,
			}
			restricted = true
		}
	}

	if !restricted {
		page = in.Page
		pageSize = in.PageSize
	}

	statusIn := modelx.UniqueInterfaces(stati, 32)
	statusMap := make(map[string][]any)
	if len(statusIn) > 0 {
		statusMap["in"] = statusIn
	}
	if in.Status != nil {
		statusMap["equalTo"] = []any{*in.Status}
	}
	filterMap[model.AttachmentColumns.PostStatus] = statusMap

	if in.ParentId != nil {
		filterMap[model.AttachmentColumns.PostParentID] = map[string][]any{
			"equalTo": {*in.ParentId},
		}
	}
	if in.AltText != nil {
		filterMap[model.AttachmentColumns.PostTitle] = map[string][]any{
			"equalTo": {strings.TrimSpace(*in.AltText)},
		}
	}
	if in.FileName != nil {
		filterMap[model.AttachmentColumns.PostName] = map[string][]any{
			"equalTo": {strings.TrimSpace(*in.FileName)},
		}
	}
	if in.Path != nil {
		filterMap[model.AttachmentColumns.Path] = map[string][]any{
			"equalTo": {strings.TrimSpace(*in.Path)},
		}
	}
	if in.UserId != nil && len(*in.UserId) > 0 {
		if i, err := strconv.ParseInt(*in.UserId, 10, 64); err == nil && i > 0 {
			filterMap[model.AttachmentColumns.PostAuthorID] = map[string][]any{
				"equalTo": {i},
			}
		}
	}
	if in.Type != nil {
		filterMap[model.AttachmentColumns.PostType] = map[string][]any{
			"equalTo": {*in.Type},
		}
	} else {
		filterMap[model.AttachmentColumns.PostType] = map[string][]any{
			"moreThan": {globalkey.AttachmentTypeDirectory},
		}
	}

	var startTimeIn []any
	var endTimeIn []any
	if in.StartTime != nil && len(strings.TrimSpace(*in.StartTime)) > 0 {
		if startTime, err := modelx.ParseLocalDate(strings.TrimSpace(*in.StartTime)); err == nil {
			startTimeIn = append(startTimeIn, startTime)
		}
	}
	if in.EndTime != nil && len(strings.TrimSpace(*in.EndTime)) > 0 {
		if endTime, err := modelx.ParseLocalDate(strings.TrimSpace(*in.EndTime)); err == nil {
			endTimeIn = append(endTimeIn, endTime)
		}
	}
	createdAtMap := make(map[string][]any)
	if len(startTimeIn) > 0 {
		createdAtMap["moreThan"] = startTimeIn
	}
	if len(endTimeIn) > 0 {
		createdAtMap["lessThanOrEqualTo"] = endTimeIn
	}
	filterMap[model.AttachmentColumns.PostDate] = createdAtMap

	var orderBy string
	if len(orderBys) > 0 {
		orderBy = strings.Join(orderBys, ",")
	}

	var search string
	if in.Search != nil && len(strings.TrimSpace(*in.Search)) > 0 {
		search = strings.TrimSpace(*in.Search)
	}
	res, count, err := l.svcCtx.MediaFile.GetList(l.ctx, model.M{
		"page":     page,
		"pageSize": pageSize,
		"orderBy":  orderBy,
		"search":   search,
	}, 1, filterMap)
	if err != nil {
		return nil, errorhandler.DefaultRepositoryError(l.Logger, err, in)
	}

	resp.Total = uint64(count)
	for _, v := range res {
		resp.List = append(resp.List, &attachment.FileInfo{
			Id:            pointy.GetPointer(strconv.FormatUint(v.ID, 10)),
			AltText:       pointy.GetPointer(v.PostTitle),
			Filename:      pointy.GetPointer(v.PostName),
			Excerpt:       pointy.GetPointer(v.PostExcerpt),
			Url:           pointy.GetPointer(v.GUID),
			UserId:        pointy.GetPointer(strconv.FormatUint(v.PostAuthorID, 10)),
			ParentId:      pointy.GetPointer(v.PostParentID),
			Type:          pointy.GetPointer(uint32(v.PostType)),
			MimeType:      pointy.GetPointer(v.PostMimeType),
			Status:        pointy.GetPointer(uint32(v.PostStatus)),
			Sort:          pointy.GetPointer(uint32(v.MenuOrder)),
			Password:      pointy.GetPointer(v.PostPassword),
			CommentStatus: pointy.GetPointer(uint32(v.CommentStatus)),
			CommentCount:  pointy.GetPointer(uint32(v.CommentCount)),
			Path:          pointy.GetPointer(v.Path),
			Size:          pointy.GetPointer(v.Size),
			Md5:           pointy.GetPointer(v.MD5),
			CreatedAt:     pointy.GetPointer(modelx.FormatTime(v.PostDate, "")),
			UpdatedAt:     pointy.GetPointer(modelx.FormatTime(v.PostModifiedDate, "")),
			DeletedAt:     pointy.GetPointer(modelx.FormatNullDotTime(v.DeletedAt, "")),
		})
	}

	return resp, nil
}
